package msgs

import (
	"encoding/binary"
	"log"
	"ospf/common"
	"ospf/tables"
)

type LinkStateUpdate struct {
	Header       Header
	NumberOfLSAs uint32
	LSA          []LinkStateAdvertisement
}

func GenLSU(lsDb *tables.OspfLSDB, ip common.ID) LinkStateUpdate {
	lsa, err := GenRouterLSA(lsDb, ip)
	if err != nil {
		log.Println("GenLSU err:", err)
	}
	lsu := LinkStateUpdate{
		Header: *GenHeader(LinkStateUpdateType, lsDb.RouterID),
		// 这边需要实现一个LSA缓冲池，转发接收到的一些LSA包。
		NumberOfLSAs: 1,
		LSA:          []LinkStateAdvertisement{&lsa},
	}
	lsu.Header.PacketLength = uint16(headerLen + 4 + lsa.Len())
	tData := make([]byte, headerLen+4+lsa.Len())
	lsu.Header.CheckSum = CalculateCheckSum(tData)
	return lsu
}

// Serialize 将对象转化为比特流
func (lsu *LinkStateUpdate) Serialize() ([]byte, error) {
	n := headerLen + 4
	// 获取LSU包的总长度
	for _, lsa := range lsu.LSA {
		n += lsa.Len()
	}
	data := make([]byte, n)
	err := lsu.Header.Serialize(data[:headerLen])
	if err != nil {
		return nil, err
	}
	binary.BigEndian.PutUint32(data[headerLen:headerLen+4], lsu.NumberOfLSAs)
	idx := headerLen + 4
	for _, lsa := range lsu.LSA {
		d, err := lsa.Serialize()
		if err != nil {
			return nil, err
		}
		copy(data[idx:idx+lsa.Len()], d)
		idx += lsa.Len()
	}
	return data, nil
}

// Deserialize data参数中，不包含header信息
func (lsu *LinkStateUpdate) Deserialize(data []byte) error {
	// pre check
	if l := len(data); l < 4 || l%4 != 0 {
		return common.ErrDeserialize("invalid data length.")
	}
	// map
	lsu.NumberOfLSAs = binary.BigEndian.Uint32(data[:4])
	lsu.LSA = make([]LinkStateAdvertisement, lsu.NumberOfLSAs)
	idx := 4
	for i := 0; i < int(lsu.NumberOfLSAs); i++ {
		lsaType := data[idx+3]
		switch LSType(lsaType) {
		case RouterLSAType:
			lsu.LSA[i] = &RouterLSA{}
		case NetworkLSAType:
			continue
		default:
			return common.ErrDeserialize("Invalid LSA type.")
		}
		err := lsu.LSA[i].Deserialize(data[idx:])
		if err != nil {
			return err
		}
		idx += lsu.LSA[i].Len()
	}
	return nil
}

func (lsu *LinkStateUpdate) GetHeader() *Header {
	return &lsu.Header
}

func (lsu *LinkStateUpdate) Len() int {
	n := headerLen + 4
	// 获取LSU包的总长度
	for _, lsa := range lsu.LSA {
		n += lsa.Len()
	}
	return n
}
